#include <Globals.h>
#include <RemoteResource.h>
#include <RpcCall.h>
#include <MemoryManagement.h>
#include <ResourceManager.h>
#include <ProcessManager.h>
#include <SyscallDispatcher.h>
#include <ProcessManager.h>

RemoteResource::RemoteResource(Callable *target, const char *name)
  : Resource(target, name)
{
  owner = processManager->getProcess()->getPid();
}

RemoteResource::~RemoteResource()
{
}

int RemoteResource::callSys(u32int id, bool synchronous, int p1, int p2, int p3, int p4, int p5)
{
  Address place = (Address)memoryManager.umalloc(sizeof(RpcCall));
  RpcCall *rpcCall = new(place) RpcCall(target, p1, p2, p3, p4, p5);

  rpcCall->nparams = -1;
  Call0 call0 = table0.lookup(id);
  if (call0)
  {
    rpcCall->call.call0 = call0;
    rpcCall->nparams = 0;
  }
  Call1 call1 = table1.lookup(id);
  if (call1)
  {
    rpcCall->call.call1 = call1;
    rpcCall->nparams = 1;
  }
  Call2 call2 = table2.lookup(id);
  if (call2)
  {
    rpcCall->call.call2 = call2;
    rpcCall->nparams = 2;
  }
  Call3 call3 = table3.lookup(id);
  if (call3)
  {
    rpcCall->call.call3 = call3;
    rpcCall->nparams = 3;
  }
  Call4 call4 = table4.lookup(id);
  if (call4)
  {
    rpcCall->call.call4 = call4;
    rpcCall->nparams = 4;
  }
  Call5 call5 = table5.lookup(id);
  if (call5)
  {
    rpcCall->call.call5 = call5;
    rpcCall->nparams = 5;
  }
  
  if (rpcCall->nparams == -1)
  {
    memoryManager.ufree(rpcCall);
    DEBUG_SPAM("Call " << hex << (u32int)rpcCall << " had no target, aborting.");
    return -1;
  }
  

  if (!synchronous)
    rpcCall->destroyable = true;
  
  rpcCall->sender = processManager->getProcess()->getPid();
  
  processManager->getProcess(owner)->queueRpcCall(rpcCall);
  
  // If this is a synchronous call...
  if (synchronous)
  {
    // Spin until it returns.
    while (!rpcCall->isComplete())
      ;

    int tmp = rpcCall->r;
    memoryManager.ufree(rpcCall);
    
    return tmp;
  }
  else
    return -1;
}

int createResource(const char *name, Callable *target)
{
  int ret;
  asm volatile("int $30" : "=a" (ret) : "0" (SYSCALL_CREATERESOURCE), "b" ((int)name), "c" ((int)target));
  return ret;
}

int addFunction(int resource, Resource::Call0 pCall, int fId)
{
  int ret;
  asm volatile("int $30" : "=a" (ret) : "0" (SYSCALL_ADDFUNC0), "b" (resource), "c" (&pCall), "d" (fId));
  return ret;
}

int addFunction(int resource, Resource::Call1 pCall, int fId)
{
  int ret;
  asm volatile("int $30" : "=a" (ret) : "0" (SYSCALL_ADDFUNC1), "b" (resource), "c" (&pCall), "d" (fId));
  return ret;
}

int addFunction(int resource, Resource::Call2 pCall, int fId)
{
  int ret;
  asm volatile("int $30" : "=a" (ret) : "0" (SYSCALL_ADDFUNC2), "b" (resource), "c" (&pCall), "d" (fId));
  return ret;
}

int addFunction(int resource, Resource::Call3 pCall, int fId)
{
  int ret;
  asm volatile("int $30" : "=a" (ret) : "0" (SYSCALL_ADDFUNC3), "b" (resource), "c" (&pCall), "d" (fId));
  return ret;
}

int addFunction(int resource, Resource::Call4 pCall, int fId)
{
  int ret;
  asm volatile("int $30" : "=a" (ret) : "0" (SYSCALL_ADDFUNC4), "b" (resource), "c" (&pCall), "d" (fId));
  return ret;
}

int addFunction(int resource, Resource::Call5 pCall, int fId)
{
  int ret;
  asm volatile("int $30" : "=a" (ret) : "0" (SYSCALL_ADDFUNC5), "b" (resource), "c" (&pCall), "d" (fId));
  return ret;
}

int destroyResource(int resource)
{
  int ret;
  asm volatile("int $30" : "=a" (ret) : "0" (SYSCALL_DESTROYRESOURCE), "b" (resource));
  return ret;
}
